#include "OISHandler.h"
#include "OgreUtil.h"

OISHandler::OISHandler() :
		gestorEntrada(NULL), teclado(NULL), raton(NULL) {
}

OISHandler::~OISHandler() {
	// Destruimos OIS
	if (gestorEntrada) {
		gestorEntrada->destroyInputObject(teclado);
		gestorEntrada->destroyInputObject(raton);
		OIS::InputManager::destroyInputSystem(gestorEntrada);
		teclado = 0;
		raton = 0;
		gestorEntrada = 0;
	}

}

void OISHandler::initialize(Ogre::RenderWindow* pWindow) {
	// Configuramos el listener de teclado OIS
	OIS::ParamList parametrosOIS;
	size_t ventanaHandle = 0;
	ostringstream ventanaHandleStr;

	pWindow->getCustomAttribute("WINDOW", &ventanaHandle);
	ventanaHandleStr << ventanaHandle;
	parametrosOIS.insert(std::make_pair(string("WINDOW"), ventanaHandleStr.str()));

#if defined OIS_WIN32_PLATFORM
	parametrosOIS.insert(std::make_pair(string("w32_mouse"), string("DISCL_FOREGROUND")));
	parametrosOIS.insert(std::make_pair(string("w32_mouse"), string("DISCL_NONEXCLUSIVE")));
	parametrosOIS.insert(std::make_pair(string("w32_keyboard"), string("DISCL_FOREGROUND")));
	parametrosOIS.insert(std::make_pair(string("w32_keyboard"), string("DISCL_NONEXCLUSIVE")));
#elif defined OIS_LINUX_PLATFORM
	parametrosOIS.insert(std::make_pair(string("x11_mouse_grab"), string("false")));
	parametrosOIS.insert(std::make_pair(string("x11_mouse_hide"), string("false")));
	parametrosOIS.insert(std::make_pair(string("x11_keyboard_grab"), string("false")));
	parametrosOIS.insert(std::make_pair(string("XAutoRepeatOn"), string("false")));
#endif

	// Creamos el gestor de entrada (con teclado y raton)
	gestorEntrada = OIS::InputManager::createInputSystem(parametrosOIS);
	teclado = static_cast<OIS::Keyboard*>(gestorEntrada->createInputObject(OIS::OISKeyboard, true));
	raton = static_cast<OIS::Mouse*>(gestorEntrada->createInputObject(OIS::OISMouse, true));

	// Pedimos que nos envien eventos de raton teclado
	raton->setEventCallback(this);
	teclado->setEventCallback(this);

}

// Actualizamos la entrada
void OISHandler::capture() {
	teclado->capture();
	raton->capture();
}

// Guardamor Camera para usarla luego para calcular coordenadas
void OISHandler::setSceneValues(Ogre::SceneManager* pSceneMgr, Ogre::Camera* pCamera) {
	mSceneMgr = pSceneMgr;
	mCamera = pCamera;
}

void OISHandler::windowClosed(Ogre::RenderWindow* mWindow) {
}

bool OISHandler::windowClosing(Ogre::RenderWindow* mWindow) {
	OgreUtil::setExitAppTriggered();
	return true;
}

void OISHandler::windowResized(Ogre::RenderWindow* mWindow) {
	cout << "Ventana redimensionada" << endl;
}

bool OISHandler::keyPressed(const OIS::KeyEvent &arg) {
	if (arg.key == OIS::KC_ESCAPE) {
		OgreUtil::setExitAppTriggered();
	}
	cout << "keyPressed: " << arg.key << endl;
	return true;
}

bool OISHandler::keyReleased(const OIS::KeyEvent &arg) {
	return true;
}

bool OISHandler::mouseMoved(const OIS::MouseEvent &arg) {
	cout << "Mouse moved. X:" << arg.state.X.abs << ",Y:" << arg.state.Y.abs << endl;

	//Calculo de coordenadas en XYZ
	Ogre::Plane mPlane(Ogre::Vector3::UNIT_Y, 0);
	Ogre::MeshManager::getSingleton().createPlane("ground", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, mPlane, 1500, 1500, 20, 20, true, 1, 1500, 1500, Ogre::Vector3::UNIT_Z);
	// get window height and width
	Ogre::Real screenWidth = Ogre::Root::getSingleton().getAutoCreatedWindow()->getWidth();
	Ogre::Real screenHeight = Ogre::Root::getSingleton().getAutoCreatedWindow()->getHeight();
	// convert to 0-1 offset
	Ogre::Real offsetX = arg.state.X.abs / screenWidth;
	Ogre::Real offsetY = arg.state.Y.abs / screenHeight;
	// set up the ray
	Ogre::Ray mouseRay = mCamera->getCameraToViewportRay(offsetX, offsetY);
	// check if the ray intersects our plane
	// intersects() will return whether it intersects or not (the bool value) and
	// what distance (the Real value) along the ray the intersection is
	std::pair<bool, Ogre::Real> result = mouseRay.intersects(mPlane);
	if (result.first) {
		// if the ray intersect the plane, we have a distance value
		// telling us how far from the ray origin the intersection occurred.
		// the last thing we need is the point of the intersection.
		// Ray provides us getPoint() function which returns a point
		// along the ray, supplying it with a distance value.
		// get the point where the intersection is
		Ogre::Vector3 point = mouseRay.getPoint(result.second);
		// position our ninja to that point
		cout << "Point. X:" << point.x << ",Y:" << point.y << ",Z:" << point.z << endl;

		mSceneMgr->destroyAllManualObjects();
		try {
			if (mSceneMgr->getSceneNode("manual1_node") != NULL) {
				mSceneMgr->destroySceneNode("manual1_node");
			}
		} catch (Ogre::Exception ex) {
		}
		Ogre::ManualObject* myManualObject = mSceneMgr->createManualObject("manual1");
		Ogre::SceneNode* myManualObjectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode("manual1_node");
		Ogre::MaterialPtr myManualObjectMaterial = Ogre::MaterialManager::getSingleton().create("manual1Material", "General");
		myManualObjectMaterial->setReceiveShadows(false);
		myManualObjectMaterial->getTechnique(0)->setLightingEnabled(true);
		myManualObjectMaterial->getTechnique(0)->getPass(0)->setDiffuse(0, 0, 1, 0);
		myManualObjectMaterial->getTechnique(0)->getPass(0)->setAmbient(0, 0, 1);
		myManualObjectMaterial->getTechnique(0)->getPass(0)->setSelfIllumination(0, 0, 1);
		//myManualObjectMaterial->dispose();  // dispose pointer, not the material
		myManualObject->begin("manual1Material", Ogre::RenderOperation::OT_LINE_LIST);
		myManualObject->position(0, 0, 0);
		myManualObject->position(point.x, 0, point.z);
		myManualObject->end();
		myManualObjectNode->attachObject(myManualObject);

	}


	return true;
}

bool OISHandler::mousePressed(const OIS::MouseEvent &arg, OIS::MouseButtonID id) {
	switch (id) {
	case OIS::MB_Left:
		break;
	case OIS::MB_Right:
		break;
	}
	return true;
}

bool OISHandler::mouseReleased(const OIS::MouseEvent &arg, OIS::MouseButtonID id) {
	switch (id) {
	case OIS::MB_Left:
		break;
	case OIS::MB_Right:
		break;
	}
	return true;
}
